﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows.Controls;
using System.Windows;
using System.Windows.Media;
using xnaGraphics = Microsoft.Xna.Framework.Graphics;
using xna = Microsoft.Xna.Framework;

namespace client.app.gui2
{
    #region IDrawCanvas
    public interface IDrawCanvas
    {
        bool Display { get; set; }
        FrameworkElement BaseElement { get; }

        void BeginDraw();
        void Update(comm.TimeStat timeStat);
        void Draw(xnaGraphics.SpriteBatch spriteBatch, xna.Vector2? position = null);
        void Draw(xnaGraphics.SpriteBatch spriteBatch, xna.Rectangle dRect, xna.Rectangle? sRect);
    }
    #endregion

    #region DrawCanvas
    public class DrawCanvas : IDrawCanvas
    {
        public bool Display
        {
            get
            {
                return BaseElement.Visibility == Visibility.Visible;
            }
            set
            {
                var vis = value ? Visibility.Visible : Visibility.Collapsed;
                if (BaseElement.Visibility != vis)
                {
                    BaseElement.Visibility = vis;
                }
            }
        }
        public FrameworkElement BaseElement { get; private set; }

        uint _changeCount = 0;
        xnaGraphics.Texture2D _tex = null;
        xna.Vector2 _position;

        public DrawCanvas(FrameworkElement element)
        {
            BaseElement = element;
            BaseElement.SizeChanged += new SizeChangedEventHandler((o, e) =>
            {
                BeginDraw();
            });
            //BaseElement.LayoutUpdated += new EventHandler((o, e) =>
            //{
            //    _changeCount++;
            //});
        }

        public void Update(comm.TimeStat timeStat)
        {
            _position = MainGame.MainWindow.GetOffset(BaseElement);
            if (Display && _changeCount > 0)
            {
                _tex = BaseElement.ToTexture2D();
                _changeCount--;

                System.Console.WriteLine(BaseElement.GetType().Name);
            }
        }
        public void BeginDraw()
        {
            _changeCount++;
        }
        public void Draw(xnaGraphics.SpriteBatch spriteBatch, xna.Vector2? position = null)
        {
            if (Display && _tex != null)
            {
                if (!position.HasValue)
                {
                    position = _position;
                }
                spriteBatch.Draw(_tex, position.Value, xna.Color.White);
            }
        }
        public void Draw(xnaGraphics.SpriteBatch spriteBatch, xna.Rectangle dRect, xna.Rectangle? sRect)
        {
            if (Display && _tex != null)
            {
                spriteBatch.Draw(_tex, dRect, sRect, xna.Color.White);
            }
        }
    }
    #endregion

    #region DrawCanvas<T>
    public class DrawCanvas<T> : DrawCanvas
    {
        public T Element { get; private set; }

        public DrawCanvas(FrameworkElement element)
            : base(element)
        {
            Element = (T)(object)element;
        }
    }
    #endregion

    #region CacheDrawCanvas
    public class CacheDrawCanvas : DrawCanvas<WrapPanel>
    {
        List<KeyValuePair<string, FrameworkElement>> _elList = new List<KeyValuePair<string, FrameworkElement>>();
        Dictionary<string, xna.Rectangle> _rectDic = new Dictionary<string, xna.Rectangle>();

        public CacheDrawCanvas()
            : base(new WrapPanel
            {
                HorizontalAlignment = HorizontalAlignment.Left,
                VerticalAlignment = VerticalAlignment.Top,
                Background = new SolidColorBrush(Color2.Transparent())
            })
        {
            BaseElement.SizeChanged += new SizeChangedEventHandler((o, e) =>
            {
                UpdateRectDic();
            });
        }

        void UpdateRectDic()
        {
            var list = _elList.ToArray();
            foreach (var kv in list)
            {
                var el = kv.Value;
                if (el.ActualWidth > 0 && el.ActualHeight > 0)
                {
                    var pt = el.TranslatePoint(new Point(), Element);
                    var rect = new xna.Rectangle((int)pt.X, (int)pt.Y, (int)el.ActualWidth, (int)el.ActualHeight);
                    if (!_rectDic.ContainsKey(kv.Key))
                    {
                        _rectDic.Add(kv.Key, rect);
                    }
                    else
                    {
                        _rectDic[kv.Key] = rect;
                    }
                }
            }
        }

        public void AddElement(FrameworkElement element)
        {
            AddElement(comm.GUID.NewString(), element);
        }
        public void AddElement(string key, FrameworkElement element)
        {
            _elList.Add(new KeyValuePair<string, FrameworkElement>(key, element));
            Element.Children.Add(element);
        }
        public void ClearElement()
        {
            _elList.Clear();
            _rectDic.Clear();
            Element.Children.Clear();
        }

        public void Draw(xnaGraphics.SpriteBatch spriteBatch, string key, xna.Vector2? position = null)
        {
            xna.Rectangle rect;
            if (_rectDic.TryGetValue(key, out rect))
            {
                if (!position.HasValue)
                {
                    position = xna.Vector2.Zero;
                }
                Draw(spriteBatch, new xna.Rectangle((int)position.Value.X, (int)position.Value.Y, (int)rect.Width, (int)rect.Height), rect);
            }
        }
    }
    #endregion

    #region DrawFrame
    public class DrawFrame
    {
        public bool Display
        {
            get { return _display; }
            set { _display = value; }
        }

        CacheDrawCanvas _drawCanvas = null;
        string _key = null;
        xna.Vector2? _position = null;
        bool _display = true;

        public DrawFrame()
        {
        }

        public void SetFrame(CacheDrawCanvas drawCanvas, string key, xna.Vector2? position = null)
        {
            _key = key;
            _position = position;
            _drawCanvas = drawCanvas;
        }

        public void Draw(xnaGraphics.SpriteBatch spriteBatch)
        {
            if (Display && _drawCanvas != null)
            {
                _drawCanvas.Draw(spriteBatch, _key, _position);
            }
        }
    }
    #endregion

    #region DrawUI
    public class DrawUI : ContentControl, IDrawCanvas
    {
        public bool Display
        {
            get
            {
                return _drawCanvas.Display;
            }
            set
            {
                _drawCanvas.Display = value;
            }
        }
        public FrameworkElement BaseElement
        {
            get { return _drawCanvas.BaseElement; }
        }

        DrawCanvas _drawCanvas = null;

        public DrawUI()
        {
            _drawCanvas = new DrawCanvas(this);
            Background = new SolidColorBrush(Color2.Transparent());
        }

        public void Update(comm.TimeStat timeStat)
        {
            _drawCanvas.Update(timeStat);
        }

        public void BeginDraw()
        {
            _drawCanvas.BeginDraw();
        }
        public void Draw(xnaGraphics.SpriteBatch spriteBatch, xna.Vector2? position = null)
        {
            _drawCanvas.Draw(spriteBatch, position);
        }
        public void Draw(xnaGraphics.SpriteBatch spriteBatch, xna.Rectangle dRect, xna.Rectangle? sRect)
        {
            _drawCanvas.Draw(spriteBatch, dRect, sRect);
        }
    }
    #endregion
}
